package com.koro.utils;

import com.koro.cache.RedisKeys;
import com.koro.constant.Constants;
import com.koro.constant.ScheduleConstants;
import com.koro.entity.JobInfo;
import com.koro.entity.JobInfoLog;
import com.koro.lock.Lock;
import com.koro.lock.RedisDistributedLockHandler;
import com.koro.service.JobInfoLogService;
import com.koro.tool.SpringUtils;
import com.koro.tool.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

/**
 * 抽象quartz调用
 */
@Slf4j
public abstract class AbstractQuartzJob implements Job {
    /**
     * 线程本地变量
     */
    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobInfo jobInfo = new JobInfo();
        BeanUtils.copyBeanProp(jobInfo, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
        Lock lock = new Lock(RedisKeys.TIMETASK + jobInfo.getInvokeTarget(), jobInfo.getJobId().toString());
        boolean getLock = SpringUtils.getBean(RedisDistributedLockHandler.class).getLock(lock);
        if (getLock) {
            try {
                before(context, jobInfo);
                if (jobInfo != null) {
                    doExecute(context, jobInfo);
                }
                after(context, jobInfo, null);
            } catch (Exception e) {
                log.error("任务执行异常  - ：", e);
                after(context, jobInfo, e);
            } finally {
                SpringUtils.getBean(RedisDistributedLockHandler.class).releaseLock(lock);
            }
        } else {
            log.error("任务:" + jobInfo.getJobName() + "已在其他机器执行!");
        }

    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param jobInfo  系统计划任务
     */
    protected void before(JobExecutionContext context, JobInfo jobInfo) {
        threadLocal.set(new Date());
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     * @param jobInfo  系统计划任务
     */
    protected void after(JobExecutionContext context, JobInfo jobInfo, Exception e) {
        Date startTime = threadLocal.get();
        threadLocal.remove();

        final JobInfoLog sysJobLog = new JobInfoLog();
        sysJobLog.setJobName(jobInfo.getJobName());
        sysJobLog.setJobGroup(jobInfo.getJobGroup());
        sysJobLog.setInvokeTarget(jobInfo.getInvokeTarget());
        sysJobLog.setStartTime(startTime);
        sysJobLog.setEndTime(new Date());
        long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime();
        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时：" + runMs + "毫秒");
        if (e != null) {
            sysJobLog.setStatus(Constants.FAIL);
            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
            sysJobLog.setExceptionInfo(errorMsg);
        } else {
            sysJobLog.setStatus(Constants.SUCCESS);
        }

        // 写入数据库当中
        SpringUtils.getBean(JobInfoLogService.class).saveJobLog(sysJobLog);
    }

    /**
     * 执行方法，由子类重载
     *
     * @param context 工作执行上下文对象
     * @param jobInfo  系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, JobInfo jobInfo) throws Exception;
}
